package com.hjy.websocket.websocketservice;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hjy.exception.CfmsErrorType;
import com.hjy.exception.CfmsException;
import com.hjy.websocket.config.AnnotationScanner;
import com.hjy.websocket.domain.*;
import com.hjy.websocket.domain.event.InfoBackEvent;
import lombok.extern.slf4j.Slf4j;
import org.java_websocket.WebSocket;
import org.java_websocket.server.DefaultSSLWebSocketServerFactory;
import org.java_websocket.server.WebSocketServer;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import java.security.KeyStore;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

//问题
//websocket 连接问题
//InfoBackEvent 未删除问题
@Slf4j
@Service
public class ICWebSocketServer extends WebSocketServer implements IICWebSocketService {
    private Map<String, InfoBackEvent> infoMap = new HashMap<>();
    private final Map<String, WebSocket> clientMap = WsData.clientMap;
    private static final Random random = new Random();
    ObjectMapper objectMapper = new ObjectMapper();

    ExecutorService executorService = Executors.newFixedThreadPool(20);

    public ICWebSocketServer() {
        super(new InetSocketAddress(9393));
        System.out.println("websocket server start");
        setupSSL();
    }

    private void setupSSL() {
        try {
            SSLContext sslContext = SSLContext.getInstance("TLS");
            KeyStore keyStore = KeyStore.getInstance("JKS");
            try (InputStream keyStoreStream = getClass().getClassLoader().getResourceAsStream("ic/yim.p12")) {
                if (keyStoreStream == null) {
                    // 文件未找到，打印日志或抛出异常
                    log.info("KeyStore file not found!");
                } else {
                    keyStore.load(keyStoreStream, "xztjj".toCharArray());
                    log.info("KeyStore loaded successfully!");
                }
            }
            KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            kmf.init(keyStore, "xztjj".toCharArray());
            sslContext.init(kmf.getKeyManagers(), null, null);
            this.setWebSocketFactory(new DefaultSSLWebSocketServerFactory(sslContext));
            this.start();

        } catch (Exception e) {
            log.error("Error setting up SSL: ", e);
        }
    }

    @Override
    public void onOpen(WebSocket conn, org.java_websocket.handshake.ClientHandshake handshake) {
        log.info("客户端连接成功");
    }

    @Override
    public void onClose(WebSocket conn, int code, String reason, boolean remote) {

        log.info("客户端断开连接");
    }


    @Override
    public void onMessage(WebSocket conn, String text) {

        log.info("接收到消息: " + text);
        if (text == null) {
            return;
        }
        String ip = conn.getRemoteSocketAddress().getAddress().toString().replaceFirst("^/", "");
        String[] split = text.split("-");
        //这是接收到的数据
        if (split[0].equals("send") && (split.length > 1)) {
            String message = split[1];
            log.info("接收到请求消息: " + text);
            //获取扫描数据
            Map<String, WsClassData> classesResult = AnnotationScanner.getClassesResult();
            WebSocketRequest webSocketRequest;
            try {
                webSocketRequest = objectMapper.readValue(message, WebSocketRequest.class);
                log.info("webSocketRequest:{}", webSocketRequest);
                //获取请求的参数
                Object[] params = webSocketRequest.getArgs();

                String methodName = webSocketRequest.getMethodName();
                //处理心跳数据
                if ("KA".equals(methodName)) {
                    dealKAData(conn, ip);
                }
                WsClassData wsClassData = classesResult.get(methodName);
                if (wsClassData == null) {
                    throw new CfmsException(CfmsErrorType.ERROR_INTERNAL_ERROR, "没有当前请求方法");
                }
                //获取加了对应的方法的bean对象
                Object bean = wsClassData.getBean();
                Class<?>[] parameterTypes = wsClassData.getMethod().getParameterTypes();
                Object[] args = new Object[parameterTypes.length];
                if (parameterTypes.length == params.length) {
                    // 检查每个参数类型 并且处理
                    for (int i = 0; i < parameterTypes.length; i++) {
                        Class<?> parameterType = parameterTypes[i];
                        Object o = convertJsonToObject(params[i].toString(), parameterType);
                        args[i] = o;
                    }
                }
                Method method = bean.getClass().getMethod(webSocketRequest.getMethodName(), parameterTypes);
                //调用方法 因为调用方法可能会被
                executorService.submit(() -> {
                    try {

                        Object invoke = method.invoke(bean, args);
                        log.info(webSocketRequest.getMethodName() + ":请求方法的返回结果" + invoke.toString());
                        if (invoke == null) {
                            invoke = "操作成功";
                        }
                        //封装参数 判断是同步还是异步 同步才会返回参数
                        if (webSocketRequest.getConnId() != null) {
                            WbsocketResponseBody success = WbsocketResponseBody.success(invoke);
                            success.setMethodName(webSocketRequest.getMethodName());
                            success.setClientIp(ip);
                            success.setConnId(webSocketRequest.getConnId());
                            backMessage(success);

                        }
                    } catch (InvocationTargetException e) {
                        //处理报错
                        WbsocketResponseBody wbsocketResponseBody = new WbsocketResponseBody();
                        Throwable targetException = e.getTargetException();
                        if (targetException instanceof CfmsException) {
                            // 如果e是CfmsException类的实例，执行相应的处理
                            CfmsException cfmsException = (CfmsException) targetException;
                            wbsocketResponseBody.setMsg("failed");
                            wbsocketResponseBody.setMsg(cfmsException.getMessage());
                        } else {
                            wbsocketResponseBody.setMsg("failed");
                            wbsocketResponseBody.setMsg("内部错误");
                        }
                        wbsocketResponseBody.setConnId(webSocketRequest.getConnId());
                        wbsocketResponseBody.setMethodName(webSocketRequest.getMethodName());
                        wbsocketResponseBody.setClientIp(ip);
                        backMessage(wbsocketResponseBody);
                    } catch (IllegalAccessException e) {
                        WbsocketResponseBody wbsocketResponseBody = new WbsocketResponseBody();
                        wbsocketResponseBody.setMsg("failed");
                        wbsocketResponseBody.setMsg("内部错误");
                        wbsocketResponseBody.setConnId(webSocketRequest.getConnId());
                        wbsocketResponseBody.setMethodName(webSocketRequest.getMethodName());
                        wbsocketResponseBody.setClientIp(ip);
                        backMessage(wbsocketResponseBody);
                        e.printStackTrace();
                        throw new CfmsException(CfmsErrorType.ERROR_INTERNAL_ERROR, "内部错误");
                    }
                });

            } catch (Exception e) {
                e.printStackTrace();
                throw new CfmsException(CfmsErrorType.ERROR_INTERNAL_ERROR, "数据异常");

            }

        } else if (split[0].equals("receive") && (split.length > 1)) {
            String connId = null;
            String message = split[1];

            try {
                WbsocketResponseBody wbsocketResponseBody = objectMapper.readValue(message, WbsocketResponseBody.class);
                connId = wbsocketResponseBody.getConnId();
                log.info("接收到回复消息: " + text);
                InfoBackEvent infoBack = infoMap.get(connId);
                if (infoBack != null) {
                    infoBack.back(wbsocketResponseBody);
                }
            } catch (JsonProcessingException e) {
                throw new CfmsException(CfmsErrorType.ERROR_INTERNAL_ERROR, "数据异常");
            } finally {
                infoMap.remove(connId);
            }
        }

    }

    @Override
    public void onError(WebSocket conn, Exception ex) {

        ex.printStackTrace();

    }

    @Override
    public void onStart() {

    }

    /**
     * 向特定的客户端发送消息：
     *
     * @param client
     * @return
     */
    public String sendMessageSToClient(WebSocket client, String message) {
        log.info("发送消息message：{}", message);
        if (client != null) {
            client.send(message.toString());
            return null;
        } else {
            return "websocket没有连接";
        }
    }

    /**
     * 向特定的客户端发送消息：
     *
     * @param client
     * @return
     */
    public void sendMessageAToClient(WebSocket client, String message) {
        log.info("发送消息message：{}", message);
        client.send(message.toString());
    }

    public void dealKAData(WebSocket webSocket, String ip) {
        Map<String, LocalDateTime> clientTimeMap = WsData.clientTimeMap;
        log.info("客户端{}连接", ip);
        clientMap.put(ip, webSocket);

        clientTimeMap.put(ip, LocalDateTime.now());

    }

    //心跳检测
    @Scheduled(fixedDelay = 500)
    public void checkKA() {
        Map<String, LocalDateTime> clientTimeMap = WsData.clientTimeMap;
        for (String ip : clientTimeMap.keySet()) {
            LocalDateTime localDateTime = clientTimeMap.get(ip);
            if (isTimeOut(localDateTime)) {
                WsData.clientTimeMap.remove(ip);
            }
        }

    }

    @Override
    public WbsocketResponseBody sendMessageSynchronous(WebSocketRequest webSocketRequest) {
        //默认超时时间是5秒
        int timeOut = 5 * 100;
        String clientIp = webSocketRequest.getClientIp();
        final WbsocketResponseBody[] body = {new WbsocketResponseBody()};
        final Boolean[] result = {false};
        //创建返回对象
        InfoBackEvent infoBackEvent = new InfoBackEvent() {
            @Override
            public void back(WbsocketResponseBody info) {
                result[0] = true;
                body[0] = info;
            }
        };

        String connId = generateUniqueId();
        if (clientIp != null) {
            //判断当前有没有客户端连接

            webSocketRequest.setConnId(connId);
            WebSocket conn = clientMap.get(clientIp);
            String request = dealWebSocketRequest(webSocketRequest);
            String requestResult = sendMessageSToClient(conn, "send-" + request);
            if (requestResult != null) {
                WbsocketResponseBody wbsocketResponseBody = new WbsocketResponseBody();
                wbsocketResponseBody.setStatus("fail");
                wbsocketResponseBody.setMsg(requestResult);
                return wbsocketResponseBody;
            }
            infoMap.put(connId, infoBackEvent);
        } else {
            throw new CfmsException(CfmsErrorType.ERROR_INTERNAL_ERROR, "请输入正确的ip");
        }

        while (true) {
            if (result[0]) {
                break;
            }
            try {
                Thread.sleep(10);
                timeOut = timeOut - 1;
                if (timeOut == 0) {
                    WbsocketResponseBody wbsocketResponseBody = new WbsocketResponseBody();
                    wbsocketResponseBody.setStatus("fail");
                    wbsocketResponseBody.setMsg("请求超时");
                    infoMap.remove(connId);
                    return wbsocketResponseBody;
                }
            } catch (Exception e) {
                throw new CfmsException(CfmsErrorType.ERROR_INTERNAL_ERROR, "程序异常");
            }
        }

        return body[0];


    }


    @Override
    public WbsocketResponseBody sendMessageSynchronous(WebSocketRequest webSocketRequest, int timeOut) {
        //默认超时时间是5秒

        //默认超时时间是5秒
        timeOut = timeOut * 100;
        String clientIp = webSocketRequest.getClientIp();
        final WbsocketResponseBody[] body = {new WbsocketResponseBody()};
        final Boolean[] result = {false};
        //创建返回对象
        InfoBackEvent infoBackEvent = new InfoBackEvent() {
            @Override
            public void back(WbsocketResponseBody info) {
                result[0] = true;
                body[0] = info;
            }
        };

        String connId = generateUniqueId();
        if (clientIp != null) {
            //判断当前有没有客户端连接
            webSocketRequest.setConnId(connId);
            WebSocket conn = clientMap.get(clientIp);
            String request = dealWebSocketRequest(webSocketRequest);
            String requestResult = sendMessageSToClient(conn, "send-" + request);
            if (requestResult != null) {
                WbsocketResponseBody wbsocketResponseBody = new WbsocketResponseBody();
                wbsocketResponseBody.setStatus("fail");
                wbsocketResponseBody.setMsg(requestResult);
                return wbsocketResponseBody;
            }
            infoMap.put(connId, infoBackEvent);
        } else {
            throw new CfmsException(CfmsErrorType.ERROR_INTERNAL_ERROR, "请输入正确的ip");
        }

        while (true) {
            if (result[0]) {
                break;
            }
            try {
                System.out.println("sleep");
                Thread.sleep(10);
                timeOut = timeOut - 1;
                if (timeOut == 0) {
                    WbsocketResponseBody wbsocketResponseBody = new WbsocketResponseBody();
                    wbsocketResponseBody.setStatus("fail");
                    wbsocketResponseBody.setMsg("请求超时");
                    infoMap.remove(connId);
                    return wbsocketResponseBody;
                }
            } catch (Exception e) {
                throw new CfmsException(CfmsErrorType.ERROR_INTERNAL_ERROR, "程序异常");
            }
        }

        return body[0];

    }

    @Override
    public void sendMessageAsynchronous(WebSocketRequest webSocketRequest) {
        String clientIp = webSocketRequest.getClientIp();

        if (clientIp != null) {
            //判断当前有没有客户端连接
            WebSocket conn = clientMap.get(clientIp);
            if (conn != null) {
                String request = dealWebSocketRequest(webSocketRequest);
                sendMessageAToClient(conn, "send-" + request);
            } else {
                log.info(clientIp + " 的客户端没有连接");
                WbsocketResponseBody wbsocketResponseBody = new WbsocketResponseBody();
                wbsocketResponseBody.setStatus("failed");
                wbsocketResponseBody.setMsg(clientIp + " 的客户端没有连接");
            }

        } else {
            throw new CfmsException(CfmsErrorType.ERROR_INTERNAL_ERROR, "请输入正确的ip");
        }
    }

    public void backMessage(WbsocketResponseBody wbsocketResponseBody) {
        String clientIp = wbsocketResponseBody.getClientIp();
        WebSocket conn = clientMap.get(clientIp);
        String responseBody = dealWebSocketWbsocketResponseBody(wbsocketResponseBody);
        sendMessageAToClient(conn, "receive-" + responseBody);

    }


    public boolean isTimeOut(LocalDateTime time) {
        LocalDateTime now = LocalDateTime.now(); // 获取当前时间
        Duration duration = Duration.between(time, now); // 计算两个时间点之间的持续时间
        return duration.toMillis() > 1500; // 判断是否超过1秒
    }

    public <T> T convertJsonToObject(String json, Class<T> parameterType) {
        ObjectMapper objectMapper = new ObjectMapper();
        try {
            return objectMapper.readValue(json, parameterType);
        } catch (JsonProcessingException e) {
            throw new CfmsException(CfmsErrorType.ERROR_INTERNAL_ERROR, "参数请求异常");

        }
    }


    private String dealWebSocketRequest(WebSocketRequest webSocketRequest) {
        try {
            ObjectMapper mapper = new ObjectMapper();
            Object[] args = webSocketRequest.getArgs();
            Object[] newArgs = new Object[args.length];
            for (int i = 0; i < args.length; i++) {
                Object arg = args[i];
                newArgs[i] = mapper.writeValueAsString(arg);

                webSocketRequest.setArgs(newArgs);
            }
            String request = mapper.writeValueAsString(webSocketRequest);
            return request;
        } catch (JsonProcessingException e) {
            throw new CfmsException(CfmsErrorType.ERROR_INTERNAL_ERROR, "参数请求异常");
        }
    }

    private String dealWebSocketWbsocketResponseBody(WbsocketResponseBody wbsocketResponseBody) {
        try {
            ObjectMapper mapper = new ObjectMapper();
            String responseBody = mapper.writeValueAsString(wbsocketResponseBody);
            return responseBody;
        } catch (JsonProcessingException e) {
            throw new CfmsException(CfmsErrorType.ERROR_INTERNAL_ERROR, "参数请求异常");
        }
    }

    public static String generateUniqueId() {
        long timestamp = System.currentTimeMillis();
        int randomNum = random.nextInt(1000); // 生成 0 到 999 的随机数
        return String.valueOf(timestamp + randomNum);
    }


}
